package xyz.scootaloo.code.draft.discrete

import xyz.scootaloo.code.common.TextTable
import xyz.scootaloo.code.common.log
import xyz.scootaloo.code.common.sortByDict
import kotlin.math.pow

/**
 * @author flutterdash@qq.com
 * @since 2021/10/9 11:48
 */

/**
 * 输出真值表
 *
 * @param block 对于接下来要输出的内容进行配置; 这个参数被忽略
 */
fun ExpressionHolder.show(block: CalculateConf.() -> Unit = {}) {
    if (!this.success)
        return

    val ctx = this.localContext
    val variateTable = ctx.variates().sortByDict()
    val conf = CalculateConf()
    conf.block()

    this.exprStr.log()

    if (conf.showVariate)
        showVariateTable(variateTable)

    if (conf.showDebugInf)
        showDebugInfo()

    if (conf.showTruthTable)
        showTruthTable(ctx, variateTable, listOf(this))
}

fun compare(vararg expr: String, block: CalculateConf.() -> Unit = {}) {
    val commonCtx = LocalContext()
    // todo
}

private fun showVariateTable(vt: List<String>) = "命题变元: $vt".log()

private fun showDebugInfo() = "暂未实现".log()

private fun showTruthTable(
    ctx: LocalContext, vt: List<String>, expressions: List<ExpressionHolder>
) {
    data class Wrapper(
        var visited: Boolean,
        val variate: String
    )

    val builder = TextTable.get()
    val cache = vt.map { v -> Wrapper(false, v) }

    fun setHeader() {
        val header = ArrayList<String>()
        header.addAll(vt)
        header.addAll(expressions.map { it.exprStr })
        builder.append(header, true)
    }

    fun collectResult(count: Int): List<String> {
        val res = ArrayList<String>()
        for (warp in cache)
            res.add(if (warp.visited) "1" else "0")
        for (holder in expressions)
            res.add(if (holder.expression.eval(ctx)) "1 (m$count)" else "0 (M$count)")
        return res
    }

    fun displayResult(count: Int) {
        builder.append(collectResult(count))
    }

    fun updateVariateTable() {
        for (wrap in cache) {
            ctx.refresh {
                this[wrap.variate] = wrap.visited
            }
        }
    }

    fun dec2bin(num: Int) {
        var base = 1
        for (idx in cache.indices) {
            cache[cache.size - idx - 1].visited = (base and num != 0)
            base = base shl 1
        }
        updateVariateTable()
        displayResult(num)
    }

    setHeader()
    for (i in 0 until 2.0.pow(cache.size.toDouble()).toInt()) {
        dec2bin(i)
    }
    builder.printOnConsole()
}

class CalculateConf(
    var showVariate: Boolean = true,
    var showTruthTable: Boolean = true,
    var showFormulaType: Boolean = true,
    var showDebugInf: Boolean = false
)
